package taller2.model.graph.algorithms;

import java.util.ArrayList;
import java.util.List;

import taller2.interfaces.Connection;
import taller2.interfaces.Graph;
import taller2.interfaces.Node;
import taller2.utils.Constants;
import taller2.utils.Constants.Colores;
import taller2.utils.Utils;

public class TransitiveLockApplicator extends AlgorithmApplicatorImpl{

    private ArrayList<String> tablas;
    private ArrayList<Integer> highligtedLines;
    private int cont;
    private static final String savePath = Constants.savedGraphsPath + "CerraduraTransitiva";
    
	public TransitiveLockApplicator(){
		super();
	}

	// applies the algorithm to the graph
	// and stores the path's and pseudocode lines
	public void solveProblem(Graph g){
		
		if(noGraph(g) || !noGraphPaths() || !noPseudocodeLines())
			return;
		
		g.killFluxes();
		g.unselectConnections();
		g.unselectNodes();

        /* si no es dirigido ni ponderado no funca!!!*/
        if(!g.isDirected())
        	return;

        List<Node> nodes = g.getNodes();
        int count = nodes.size();
        int[][] path = new int[count][count];

        for(int i = 0; i < count; i++){
        	for(int j = 0; j < count; j++){
            	if(i==j)
                	path[i][j] = 0;
            	else
                	path[i][j] = Constants.Inf;
         	}
      	}

        for(int i=0; i<nodes.size();i++){
        	Node node = nodes.get(i);
            node.setId(i);
        }

      	for (Node node : nodes){
        	for(Connection connection : node.getConnections()){
            	int i = node.getNumberId();
                int j = connection.getOtherNode().getNumberId();

                if (i != j)
                	path[i][j] = connection.getWeight();
         	}
     	}

        for(int k = 0; k < count; k++) {
        	for (int i = 0; i < count; i++) {
            	for (int j = 0; j < count; j++) {
            		if (i != j){
            			int distance = path[i][k] + path[k][j];

            			if (path[i][j] > distance)
                        	path[i][j] = distance;
                	}
            	}
        	}
        }

        cont = 0;
		g.killWeights();		
        g.save(savePath+cont);

        guardar(savePath+cont,1,null,0,-1);
        cont++;

        guardar(savePath+cont,1,path,count,-1);

        // new UserImputWindow(formatearTabla(path,count));
            
        buscarUnosYCeros(path, count, g);
        g.save(savePath+cont);
        guardar(savePath+cont,7,path,count,-1);
        cont++;

        g.load(savePath+0);
	}


    private void buscarUnosYCeros(int[][] path, int count, Graph g) {
        for(int i=0; i<count ; i++) {
            for (int j = 0; j < count; j++) {
                if(path[i][j] != Constants.Inf) {
                    path[i][j] = 1;
                    
                    Node n1 = g.getNodeByIndex(i);
                    Node n2 = g.getNodeByIndex(j);
                    
                    if((n1 != null)&&(n2 != null)){
                    	n1.changeColor(Colores.green);
                    	n2.changeColor(Colores.purple);
                    	
                    	g.save(savePath+cont);                    
                    	
                    	n1.changeColor(Colores.yellow);
                    	n2.changeColor(Colores.yellow);
                    }else{
                    	g.save(savePath+cont);
                    }
                    
                    
                    guardar(savePath+cont,4,path,count,calcularNumeroResaltado(path,count));
                    this.cont++;
                }else {
                    path[i][j] = 0;
                    g.save(savePath+cont);
                    guardar(savePath+cont,5,path,count,calcularNumeroResaltado(path,count));
                    this.cont++;
                }
            }
        }
    }
    
    private int calcularNumeroResaltado(int tabla[][],int tam){
        String tablaActual = tablas.get(tablas.size()-1);
        String tablaAnterior = tablas.get(tablas.size()-2);

        return buscarDiferenciasEntreTablas(tablaActual,tablaAnterior,tam);
    }

    private void guardar(String pathGrafo,int lineaPseudocodigo,int[][] tabla,int tamTabla, int numeroResaltado){
        graphPaths.add(pathGrafo);
        pseudocodeLines.add(lineaPseudocodigo);
        guardarTabla(tabla,tamTabla);

        highligtedLines.add(numeroResaltado);
    }

    private void guardarTabla(int tabla[][],int tam){
        String tablaFormateada = formatearTabla(tabla,tam);
        tablas.add(tablaFormateada);
    }

    private int buscarDiferenciasEntreTablas(String tablaActual,String tablaAnterior,int tam) {
        for(int i=0; i<tam ; i++){
            for(int j=0; j<tam ; j++){
                int valor = Utils.obtenerPos(tablaActual, i, j, tam, "[", "]");
                int valor2 = Utils.obtenerPos(tablaAnterior,i,j,tam,"[","]");

                if(valor != valor2)
                    return Utils.matrixPositionToArrayPosition(i,j,tam);
            }
        }
        return -1;
    }

    private String formatearTabla(int tabla[][],int tam){
        String tablaFormateada = "";

        if(tabla != null){
            tablaFormateada+= "\n\t";

            for(int i=0;i<tam;i++)
                tablaFormateada+= String.valueOf(i)+"\t   ";
            tablaFormateada+= "\n";

            for(int i=0;i<tam;i++){
                tablaFormateada+= String.valueOf(i);
                for(int j=0;j<tam;j++){
                    String term;
                    if(tabla[i][j] != Constants.Inf)
                        term = String.valueOf(tabla[i][j]);
                    else
                        term = "Inf";

                    tablaFormateada+= "\t[" + term + "]  ";
                }
                tablaFormateada+= "\n";
            }
            tablaFormateada+= "\n";
        }
        return tablaFormateada;
    }

    @Override
    public String getAuxText(){
        if (noTables())
            return "";

        String line = tablas.get(position);
        return line;
    }

    public String getLastTable(){
    	if(tablas == null || tablas.isEmpty())
    		return "";
    	
    	return tablas.get(tablas.size()-2);
    }
    
    public String getFirstTable(){
    	if(tablas == null || tablas.isEmpty())
    		return "";

    	return tablas.get(1);
    }
    
    // returns true if the list of tables is empty
    private boolean noTables(){
        return (tablas == null) || (tablas.isEmpty());
    }

    // resets the applicator to change the graph
    // and solve the problem again
    public void reset(){
        tablas = new ArrayList<String>();
        highligtedLines = new ArrayList<Integer>();
        graphPaths = new ArrayList<String>();
        pseudocodeLines = new ArrayList<Integer>();
        auxText = new ArrayList<String>();
        position = 0;
    }

    public void save(String path){
    };

    public void load(String path){
    }

    @Override
    public int getHighlightedWordNumber() {
        if(highligtedLines.isEmpty())
            return -1;
        return highligtedLines.get(position);
    };
}
